/*
* usbhdemo.c                                                Version 3.00
*
* smxUSBH Standalone Demo.
*
* Copyright (c) 2005-2018 Micro Digital Inc.
* All rights reserved. www.smxrtos.com
*
* This software is confidential and proprietary to Micro Digital Inc.
* It has been furnished under a license and may be used, copied, or
* disclosed only in accordance with the terms of that license and with
* the inclusion of this header. No title to nor ownership of this
* software is hereby transferred.
*
* Author: Yingbo Hu and XiaoYi Chen
*
* Portable to any ANSI compliant C compiler.
*
*****************************************************************************/

#define SMXUSBH
//#define SMXFS
#include "smxbase.h"
#include "smxusbh.h"
//#if defined(SMXFS)
#include "smxfs.h"
//#endif
#if defined(SB_CPU_MCF5445x)
#include "cfdefs.h"
#endif
#include "if_v.h"
#include "aos/kv.h"

#define DEMO_AUDIO   SU_AUDIO
#define DEMO_CCID    SU_CCID
#define DEMO_MOUSE   SU_MOUSE
#define DEMO_NET     SU_NET
#define DEMO_KBD     SU_KBD
#define DEMO_STORAGE (SU_MSTOR && !defined(SMXFS) && !defined(SMXCD))
#define DEMO_PRINTER SU_PRINTER  /* see the comment below */
#define DEMO_CDCACM  SU_CDCACM
#define DEMO_UF8000  SU_UF8000
#define DEMO_FTDI232 SU_FTDI232
#define DEMO_PL2303  SU_PL2303
#define DEMO_HID     SU_HID
#define DEMO_SERIAL  SU_SERIAL
#define DEMO_VIDEO   SU_VIDEO

/* Implemented in main.c */
extern void UartPutString(const char * pInfo);
extern unsigned char UartGetChar(void);

#if DEMO_MOUSE
static char g_TempBuf[128];
static char g_TempBuf1[32];
#endif

#if DEMO_AUDIO
#define ONLY_TEST_PLAYBACK 1
#if ONLY_TEST_PLAYBACK
#include "sounds.h"
#else
#define AUDIO_BUF_SIZE 409600
static u8 *g_pRecData;
#endif
static u8 *g_pPlaybackData;

#define MIDI_LOOP       (5)
u8 *MIDIBuf = 0;;
u8 MIDIOutData[] = {0x4, 0xF0, 0x7E, 0x00, 0x07, 0x06, 0x01, 0xF7, 0x00, 0x00, 0x00, 0x00}; /* MIDI data to send to MIDI device */
char MIDIStrBuf[128];

static void TestAudio(void);
#endif
#if DEMO_CCID
static int g_CCIDOpen = 0;
static void TestCCID(void);
#endif
#if DEMO_MOUSE
static void USBMouseHandler(SU_MOUSE_MSG * mouseMsg);
static void CheckMouseMsg(void);
#endif
#if DEMO_NET
static void CheckNetData(void);
#endif
#if DEMO_KBD
static void USBKBDHandler(u32 key_dword);
static void CheckKBDMsg(void);
#endif
#if DEMO_HID
static void USBHIDHandler(uint iID, SU_HID_FIELD_INFO *pFieldInfo, SU_HID_USAGE_INFO *pUsageInfo, s32 data);
static void CheckHIDMsg(void);
#endif
#if DEMO_STORAGE
// static void TestMassStorage(void);
static void TestMassReader(void);
#endif
#if DEMO_PRINTER
static void PrintOut(void);
#endif
#if DEMO_CDCACM
static void TestModem(void);
#endif
#if DEMO_UF8000
static void TestUF8000(void);
#endif
#if DEMO_FTDI232
static int usb_ftdi232_data_ready = 0;
static int Opened = 0;
static u8 *g_pFTDI232Buf;
static int g_iFTDI232Received = 0;
static void FTDI232Receive(void);
static void FTDI232Send(void);
#endif
#if DEMO_PL2303
static u8 *g_pPL2303Buf;
void PL2303Handle(uint iID, u16 wNewLineState);
static void PL2303Receive(void);
static void PL2303Send(void);
#endif
#if DEMO_SERIAL
static void SerialCheck(void);
void SerialHandle(uint iID, u16 wNewLineState);
#endif
#if DEMO_VIDEO
#if 0
#define VIDEO_CAPTURE_FORMAT          SU_VIDEO_FORMAT_MJPEG
#define VIDEO_CAPTURE_WIDTH           640
#define VIDEO_CAPTURE_HEIGHT          480
#else
#define VIDEO_CAPTURE_FORMAT          SU_VIDEO_FORMAT_UNCOMPRESSED
#define VIDEO_CAPTURE_WIDTH           320
#define VIDEO_CAPTURE_HEIGHT          240
#endif

#define VIDEO_CAPTURE_FRAME_INTERVAL  333333 /* 33.33 ms, 30fps */

#define VIDEO_STILL_FORMAT            SU_VIDEO_FORMAT_UNCOMPRESSED
#define VIDEO_STILL_WIDTH             320
#define VIDEO_STILL_HEIGHT            240

#if defined(SB_CPU_AT91SAM9M10_G45) && (VIDEO_CAPTURE_FORMAT == SU_VIDEO_FORMAT_UNCOMPRESSED)
#define VIDEO_DISPLAY                 1
#else
#define VIDEO_DISPLAY                 0
#endif
#if VIDEO_DISPLAY
u8 *g_pFrameBuffer = NULL;
extern void InitializeLcd(void *framebuffer, uint width, uint height);
#endif
static u8 *pCaptureBuffer[2] = { NULL, NULL };
uint g_iCurrentIndex = 0;
void TestVideo(void);
#endif


static void USBHPutString(const char * pInfo);
int USBHDemoStart(void);
int USBHDemo(void)
{
    static int initFlag = 0;

    if(0 == initFlag){
        extern void setUsbClkEnble();
        setUsbClkEnble();
        USBHDemoStart();

        initFlag = 1;
    }

#if !SB_MULTITASKING
    su_CheckRoothubStatus();
#endif
#if DEMO_AUDIO
    TestAudio();
#endif
#if DEMO_CCID
    TestCCID();
#endif
#if DEMO_MOUSE
    CheckMouseMsg();
#endif
#if DEMO_NET
    CheckNetData();
#endif
#if DEMO_KBD
    CheckKBDMsg();
#endif
#if DEMO_HID
    CheckHIDMsg();
#endif
#if DEMO_STORAGE
    //TestMassStorage();
    TestMassReader();
#endif
#if DEMO_PRINTER
    PrintOut();
#endif
#if DEMO_CDCACM
    TestModem();
#endif
#if DEMO_UF8000
    TestUF8000();
#endif
#if DEMO_FTDI232
    FTDI232Receive();
    FTDI232Send();
#endif
#if DEMO_PL2303
    PL2303Receive();
    PL2303Send();
#endif
#if DEMO_SERIAL
    SerialCheck();
#endif
#if DEMO_VIDEO
    TestVideo();
#endif
    return 0;
}


int USBHDemoStart(void)
{
    int result = -1;
#if defined(SB_CPU_MCF5445x)
    if(MCF_USB_OTG_OTGSC&MCF_USB_OTG_OTGSC_ID)
        return -1;
#endif
    USBHPutString("smxUSBH Demo Started.");
    if(su_Initialize())
    {
#if DEMO_AUDIO
#if ONLY_TEST_PLAYBACK
        g_pPlaybackData = (u8 *)pStereoSoundData;
#endif
#endif
#if DEMO_MOUSE
        su_MouseSetCallback(USBMouseHandler);
#endif
#if DEMO_KBD
        su_KbdSetCallback(USBKBDHandler);
#endif
#if DEMO_HID
        su_HIDSetCallback(USBHIDHandler);
#endif
#if 1//defined(SMXFS)
        if(sfs_init() == SB_FAIL)
           {
        	  USBHPutString("sfs_init() failed.");
              return -1;
           }

        sfs_devreg(sfs_GetUSB0Interface(), 0);
#endif
#if DEMO_FTDI232
        g_pFTDI232Buf = (u8 *)malloc(1024);
#endif
#if DEMO_PL2303
        g_pPL2303Buf = (u8 *)malloc(SU_PL2303_MTU);
        su_PL2303LineStateChangeNotify(PL2303Handle);
#endif
#if DEMO_SERIAL
        su_SerialLineStateChangeNotify(SerialHandle);
#endif

#if DEMO_VIDEO
#if VIDEO_DISPLAY
        g_pFrameBuffer = (u8 *)malloc(VIDEO_CAPTURE_WIDTH*VIDEO_CAPTURE_HEIGHT*2);
        if(g_pFrameBuffer)
        {
            int i;
            InitializeLcd((char *)g_pFrameBuffer, VIDEO_CAPTURE_WIDTH, VIDEO_CAPTURE_HEIGHT);
            memset(g_pFrameBuffer, 0xFF, VIDEO_CAPTURE_WIDTH*VIDEO_CAPTURE_HEIGHT*2);
            for(i = 0; i < VIDEO_CAPTURE_WIDTH*VIDEO_CAPTURE_HEIGHT*2;)
            {
                int R, G, B;
                R = 255;
                G = 0;
                B = 0;
                g_pFrameBuffer[i++]  = (u8) (((G & 0x3c) << 3) | (B >> 3));
                g_pFrameBuffer[i++]  = (u8) ((R & 0xf8) | (G >> 5));;
            }
        }
        else
        {
            return -1;
        }
#endif
#endif
        result = 0;
    }
    else
    {
        USBHPutString("su_Initialize() failed.");
    }

    return result;
}

int USBHDemoStop(void)
{
    if(su_USBInited())
    {
#if defined(SMXFS)
    sfs_exit();
#endif
#if DEMO_FTDI232
    free(g_pFTDI232Buf);
#endif
#if DEMO_PL2303
    free(g_pPL2303Buf);
#endif
#if DEMO_CCID
    if(g_CCIDOpen)
    {
        su_CCIDClose(0);
    }
#endif
#if DEMO_AUDIO
#if !ONLY_TEST_PLAYBACK
    if(g_pRecData)
        free(g_pRecData);
    if(g_pPlaybackData)
        free(g_pPlaybackData);
#endif
    if (MIDIBuf)
        free(MIDIBuf);

#endif
#if DEMO_VIDEO
#if VIDEO_DISPLAY
    if(g_pFrameBuffer)
        free(g_pFrameBuffer);
#endif
#endif
    su_Release();
    USBHPutString("USBHDemo exit.");
    }
    return 0;
}

/*==========================================================================*/

static void USBHPutString(const char * pInfo)
{
    printf("%s\r\n", pInfo);
}

#if DEMO_AUDIO

static void TestAudio(void)
{
    int iVolume, iVolMin, iVolMax, iVolRes;
    int iChannelNum;
    int iPlaybackID;
    uint i;
#if !ONLY_TEST_PLAYBACK
    uint iMute;
    uint iCurChan;
    int iRecordingID;
    uint iTotalRecorded;
    int ReadCount;
#else
    uint iPlaybackLoop;
#endif
    uint iTotalPlaybacked;
    int WrittenCount;
    uint iTotalLength;

    if(su_AudioInserted(0))
    {
#if !ONLY_TEST_PLAYBACK
        if ((g_pRecData == 0 ) && ((g_pRecData = (u8 *)malloc(AUDIO_BUF_SIZE)) == 0))
        {
            USBHPutString("Failed allocating g_pRecData");
            return;
        }

        if ((g_pPlaybackData == 0 ) && ((g_pPlaybackData = (u8 *)malloc(2 * AUDIO_BUF_SIZE)) == 0))
        {
            USBHPutString("Failed allocating g_pRecData");
            free(g_pRecData);
            return;
        }

        USBHPutString("Testing Record.......");
        /* first we will find which device support recording
           USB speaker does not support recording so the channel number is 0
        */
        iRecordingID = -1;
        for(i = 0; i < SU_AUDIO; i++)
        {
            iChannelNum = su_AudioRecGetChannelNum(i);
            if(iChannelNum > 0)
            {
                iRecordingID = i;
                break;
            }
        }
        if(iRecordingID >= 0)
        {
            /* make sure the format is supported */
            if(0 == su_AudioRecSetFormat(iRecordingID, SU_AUDIO_FORMAT_PCM, 44100, 16, 1))
            {
                iChannelNum = su_AudioRecGetChannelNum(iRecordingID);
                for(i = 0; i < (uint)iChannelNum; i++)
                {
                    /* get the information */
                    su_AudioRecGetCurChannel(iRecordingID, &iCurChan);
                    /* set the current recording channel */
                    su_AudioRecSelectChannel(iRecordingID, i + 1);
                    /* get volume information*/
                    su_AudioRecGetCurVolume(iRecordingID, i, &iVolume, &iVolMax, &iVolMin, &iVolRes);
                    su_AudioRecGetCurMute(iRecordingID, i, &iMute);
                    /* set volume */
                    su_AudioRecSetVolume(iRecordingID, i, iVolMax);
                    su_AudioRecSetMute(iRecordingID, i, 0);
                    /* open device first */
                    if(0 == su_AudioRecOpen(iRecordingID))
                    {
                        /* grab data to the memory */
                        iTotalRecorded = 0;
                        do
                        {
                            ReadCount = su_AudioRecRead(iRecordingID, g_pRecData + iTotalRecorded, 4*2048);
                            if(ReadCount < 0)
                                break;
                            iTotalRecorded += ReadCount;
                        }while(iTotalRecorded < (AUDIO_BUF_SIZE - 4*2048));
                        /* finally close it */
                        su_AudioRecClose(iRecordingID);
                    }
                    else
                    {
                        USBHPutString("Recording failed");
                    }
                }
            }
            else
            {
                USBHPutString("Recording @ 44100, 16bits, mono is not supported");
                return;
            }
            USBHPutString("Processing Data.......");
            if(iTotalRecorded < (AUDIO_BUF_SIZE - 4*2048))
                return;
            /* convert mono to stereo */
            for(i = 0; i < (uint)iTotalRecorded; i+=2)
            {
                g_pPlaybackData[2*i] = g_pRecData[i];
                g_pPlaybackData[2*i+1] = g_pRecData[i+1];
                g_pPlaybackData[2*i+2] = g_pRecData[i];
                g_pPlaybackData[2*i+3] = g_pRecData[i+1];
            }
            iTotalLength = iTotalRecorded*2;
        }
#else
        iTotalLength = sizeof(pStereoSoundData);
#endif
        /* find the device which support playback */
        iPlaybackID = -1;
        for(i = 0; i < SU_AUDIO; i++)
        {
            iChannelNum = su_AudioPlaybackGetChannelNum(i);
            if(iChannelNum > 0)
            {
                iPlaybackID = i;
                break;
            }
        }
        if(iPlaybackID >=0 )
        {
            /* make sure the format is matched */
            if(0 == su_AudioPlaybackSetFormat(iPlaybackID, SU_AUDIO_FORMAT_PCM, 44100, 16, 2))
            {
                USBHPutString("Testing Playback.......");
                iChannelNum = su_AudioPlaybackGetChannelNum(iPlaybackID);
                if(iChannelNum < 1)
                    return;
                /* get volume information */
                su_AudioPlaybackSetMute(iPlaybackID, 0, 0);
                for(i = 1; i <= (uint)iChannelNum; i++)
                {
                    if(0 == su_AudioPlaybackGetCurVolume(iPlaybackID, i, &iVolume, &iVolMax, &iVolMin, &iVolRes))
                    {
                        /* set volume information */
                        su_AudioPlaybackSetVolume(iPlaybackID, i, iVolMax - 1);
                    }
                }
                /* open device first */
                if(0 == su_AudioPlaybackOpen(iPlaybackID))
                {
                    iTotalPlaybacked = 0;
                    WrittenCount = 0;
#if ONLY_TEST_PLAYBACK
                    iPlaybackLoop = 1;
#endif
                    while(WrittenCount >= 0)
                    {
                        /* then send the data to the device */
                        do
                        {
                            WrittenCount = su_AudioPlaybackWrite(iPlaybackID, g_pPlaybackData + iTotalPlaybacked, 4*2048);
                            if(WrittenCount < 0)
                                break;
                            iTotalPlaybacked += WrittenCount;
                        }while((int)iTotalPlaybacked < (iTotalLength - 4*2048));
#if ONLY_TEST_PLAYBACK
                        /* reuse the buffer for 10 times */
                        if((iPlaybackLoop++)%10 == 0)
                            break;
                        else
                            iTotalPlaybacked = 0;
#else
                        break;
#endif
                    }
                    /* finally close it */
                    su_AudioPlaybackClose(iPlaybackID);
                }
                else
                {
                    USBHPutString("Playback failed");
                }
            }
            else
            {
                USBHPutString("Playback @ 44100, 16bits, stereo is not supported");
            }
        }
        else
        {
            USBHPutString("USB Audio does not support playback");
        }
    }
    else if (su_MIDIInserted(0)) /* MIDI interface */
    {
        char temp[5];
        memset(temp, 0, 5);
        temp[0] = '0';
        temp[1] = 'x';
        u16 dataCount = 0;

        if ((MIDIBuf == 0) && (MIDIBuf = (u8* )malloc(64)) == 0)
        {
            USBHPutString("Failed to allocate MIDIBuf");
            return;
        }

        /* Test MIDI data write */
        memcpy(MIDIBuf, MIDIOutData, 12);
        USBHPutString("Test Sending MIDI Data...");
        u16 loopCount = 0;
        if (su_MIDIOutCableNum(0) == -1)
        {
            /* the connected MIDI device may not have OUT MIDI stream port */
            USBHPutString("No MIDI OUT cable number detected");
        }
        else
        {
            while (loopCount < MIDI_LOOP)
            {
                dataCount = su_MIDIWrite(0, MIDIBuf, sizeof(MIDIOutData));
                memset(MIDIStrBuf, 0, 128);
                strcat(MIDIStrBuf, "MIDI Data Sent: ");
                _ultoa(dataCount, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                strcat(MIDIStrBuf, " bytes, loop ");
                _ultoa(loopCount, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                strcat(MIDIStrBuf, ":");
                _ultoa(MIDI_LOOP, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                USBHPutString(MIDIStrBuf);
                loopCount++;
                sb_OS_WAIT_MSEC_MT(1000);
            }
        }

        /* Test MIDI data read */
        loopCount = 0;
        dataCount = 0;
        memset(MIDIBuf, 0, 64);
        USBHPutString("Test Receiving MIDI Data...(Please hit the MIDI keys)");
        while (loopCount < MIDI_LOOP)
        {
            dataCount = su_MIDIRead(0, MIDIBuf, 64, 100);
            if((dataCount >0) && (dataCount <= 64))
            {
                memset(MIDIStrBuf, 0, 128);
                strcat(MIDIStrBuf, "MIDI Data Received: ");
                _ultoa(dataCount, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                strcat(MIDIStrBuf, " bytes, loop ");
                _ultoa(loopCount, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                strcat(MIDIStrBuf, ":");
                _ultoa(MIDI_LOOP, &temp[2], 16);
                strcat(MIDIStrBuf, temp);
                USBHPutString(MIDIStrBuf);

                memset(MIDIStrBuf, 0, 128);
                for (i = 0; i < dataCount; i++)
                {
                    _ultoa(MIDIBuf[i], &temp[2], 16);
                    strcat(MIDIStrBuf, temp);
                    strcat(MIDIStrBuf, ",");
                    if (((i + 1) % 8 == 0) || (i + 1) == dataCount)
                    {
                        USBHPutString(MIDIStrBuf);
                        memset(MIDIStrBuf, 0, 128);
                    }
                }

                loopCount++;
            }
            sb_OS_WAIT_MSEC_MT(100);
        }
    }
}
#endif

#if DEMO_CCID

static void TestCCID(void)
{
    uint iID = 0;
    int status;
    int i;
    SU_CCID_CONFIGURATION Config;
    u32 dwClockFreqArray[16];
    u32 dwDataRatesArray[128];
    if(su_CCIDInserted(iID))
    {
        if(!g_CCIDOpen)
        {
            Config.bMaxSlotIndex = 0;
            su_CCIDGetConfiguration(iID, &Config);
            g_CCIDOpen = (su_CCIDOpen(iID) == 0);
            if(g_CCIDOpen)
            {
                if(su_CCIDGetClockFreq(iID, dwClockFreqArray, 16*sizeof(u32)) < 0)
                {
                    USBHPutString("GetClockFreq failed");
                }
                if(su_CCIDGetDataRates(iID, dwDataRatesArray, 128*sizeof(u32)) < 0)
                {
                    USBHPutString("GetDataRates failed");
                }
            }
        }
        if(g_CCIDOpen == 0)
        {
            USBHPutString("Open CCID device failed");
            return;
        }
        else
        {
            for(i = 0; i <= Config.bMaxSlotIndex; i++)
            {
                status = su_CCIDGetSlotStatus(iID, i);
                if(status < 0)
                {
                    USBHPutString("GetSlotStatus failed");
                }
                else
                {
                    switch(status)
                    {
                    case SU_CCID_ICC_PRESENT_AND_ACTIVE:
                        USBHPutString("ICC Present and Active");
                        break;
                    case SU_CCID_ICC_PRESENT_AND_INACTIVE:
                        USBHPutString("ICC Present and Inactive");
                        break;
                    case SU_CCID_NO_ICC_PRESENT:
                        USBHPutString("No ICC Present");
                        break;
                    }
                }
                if(su_CCIDICCPowerOn(iID, i) < 0)
                {
                    USBHPutString("ICCPowerOn failed");
                }
                else
                {
                    su_CCIDICCPowerOff(iID, i);
                }
            }
        }
    }
}
#endif

#if DEMO_MOUSE
static SU_MOUSE_MSG g_mouseMsg;
static int g_getMouseMsg = 0;

static void USBMouseHandler(SU_MOUSE_MSG * mouseMsg)
{
    //TODO: add the data to the ring buffer
    g_getMouseMsg = 1;
    memcpy(&g_mouseMsg, mouseMsg, sizeof(SU_MOUSE_MSG));
}

static void CheckMouseMsg(void)
{
    if(g_getMouseMsg == 1)
    {
        strcpy(g_TempBuf, g_mouseMsg.button&SU_MOUSE_BTN_LEFT?"L":" ");
        strcat(g_TempBuf, g_mouseMsg.button&SU_MOUSE_BTN_MIDDLE?"M":" ");
        strcat(g_TempBuf, g_mouseMsg.button&SU_MOUSE_BTN_RIGHT?"R":" ");
        strcat(g_TempBuf, g_mouseMsg.button&SU_MOUSE_BTN_SIDE?"S":" ");
        strcat(g_TempBuf, g_mouseMsg.button&SU_MOUSE_BTN_EXTRA?"E":" ");

        strcat(g_TempBuf, "X: ");
        _ultoa(g_mouseMsg.x, g_TempBuf1, 10);
        strcat(g_TempBuf, g_TempBuf1);
        strcat(g_TempBuf, "Y: ");
        _ultoa(g_mouseMsg.y, g_TempBuf1, 10);
        strcat(g_TempBuf, g_TempBuf1);
        strcat(g_TempBuf, (g_mouseMsg.wheel == SU_MOUSE_WHEEL_UP)?"W:U":"W:D");
        USBHPutString(g_TempBuf);
        g_getMouseMsg = 0;
    }

}
#endif

#if DEMO_NET
static void CheckNetData(void)
{
    su_CheckNetData(0);
    /* You may need to add TCP/IP stack code here for full feature testing */
}
#endif

#if DEMO_KBD

static u32 g_KeyCode;
static int g_getKBDMsg = 0;

static void USBKBDHandler(u32 key_dword)
{
    g_getKBDMsg = 1;
    g_KeyCode = key_dword;
}

#define ALT    (ShiftFlags & SB_KBD_FL_ALT)
#define CTRL   (ShiftFlags & SB_KBD_FL_CTRL)
#define SHIFT  (ShiftFlags & (SB_KBD_FL_LSHIFT | SB_KBD_FL_RSHIFT))
#define SCROLL (ShiftFlags & SB_KBD_FL_SCROLL)
#define NUM    (ShiftFlags & SB_KBD_FL_NUM)
#define CAPS   (ShiftFlags & SB_KBD_FL_CAPS)
#define INS    (ShiftFlags & SB_KBD_FL_INS)

#define brk            0x80  // means key was pressed (OR'ed with scan code)

static unsigned char smxKeyTable[0x5e][4] =
                /* base,Shft,Ctrl,Alt */
       /* 0h */  {{  0,   0,   0, 0},
                  { 27,  27,  27, 0}, /* Esc */
                  {'1', '!',   0, 0},
                  {'2', '@',   0, 0},
                  {'3', '#',   0, 0},
                  {'4', '$',   0, 0},
                  {'5', '%',   0, 0},
                  {'6', '^',   0, 0},
       /* 8h */   {'7', '&',   0, 0},
                  {'8', '*',   0, 0},
                  {'9', '(',   0, 0},
                  {'0', ')',   0, 0},
                  {'-', '_',  31, 0},
                  {'=', '+',   0, 0},
                  {  8,   8, 127, 0}, /* Backspace */
                  {  9,   0,   0, 0}, /* Tab */
      /* 10h */   {'q', 'Q',  17, 0},
                  {'w', 'W',  23, 0},
                  {'e', 'E',   5, 0},
                  {'r', 'R',  18, 0},
                  {'t', 'T',  20, 0},
                  {'y', 'Y',  25, 0},
                  {'u', 'U',  21, 0},
                  {'i', 'I',   9, 0},
      /* 18h */   {'o', 'O',  15, 0},
                  {'p', 'P',  16, 0},
                  {'[', '{',  27, 0},
                  {']', '}',  29, 0},
                  { 13,  13,  10, 0}, /* Enter */
                  {  0,   0,   0, 0},
                  {'a', 'A',   1, 0},
                  {'s', 'S',  19, 0},
      /* 20h */   {'d', 'D',   4, 0},
                  {'f', 'F',   6, 0},
                  {'g', 'G',   7, 0},
                  {'h', 'H',   8, 0},
                  {'j', 'J',  10, 0},
                  {'k', 'K',  11, 0},
                  {'l', 'L',  12, 0},
                  {';', ':',   0, 0},
      /* 28h */   { 39, '"',   0, 0},
                  {'`', '~',   0, 0},
                  {  0,   0,   0, 0},
                  { 92, '|',  28, 0},
                  {'z', 'Z',  26, 0},
                  {'x', 'X',  24, 0},
                  {'c', 'C',   3, 0},
                  {'v', 'V',  22, 0},
      /* 30h */   {'b', 'B',   2, 0},
                  {'n', 'N',  14, 0},
                  {'m', 'M',  13, 0},
                  {',', '<',   0, 0},
                  {'.', '>',   0, 0},
                  {'/', '?',   0, 0},
                  {  0,   0,   0, 0},
                  {'*',   0, 114, 0},
      /* 38h */   {  0,   0,   0, 0},
                  {' ', ' ', ' ', 0},
                  {  0,   0,   0, 0},
                 {0xf5,   0,0xe1, 0xeb}, /* F1 */
                 {0xf4,   0,0xe0, 0xea}, /* F2 */
                 {0xf3,   0,0xdf, 0xe9}, /* F3 */
                 {0xf2,   0,0xde, 0xe8}, /* F4 */
                 {0xf1,   0,0xdd, 0xe7}, /* F5 */
      /* 40h */  {0xf0,   0,0xdc, 0xe6}, /* F6 */
                 {0xef,   0,0xdb, 0xe5}, /* F7 */
                 {0xee,   0,0xda, 0xe4}, /* F8 */
                 {0xed,   0,0xd9, 0xe3}, /* F9 */
                 {0xec,   0,0xd8, 0xe2}, /* F10 */
                  {  0,   0,   0, 0},    /* Num Lock */
                  {  0,   0,   3, 0},    /* Scroll Lock */
                 {0xff, '7',   0, 0},    /* Home */
      /* 48h */  {0xf9, '8',   0, 0},    /* cursor up */
                 {0xfb, '9',   0, 0},    /* Pg Up */
                  {'-', '-',   0, 0},    /* gray minus */
                 {0xf7, '4',   0, 0},    /* cursor left */
                  {  0, '5',   0, 0},    /* center key */
                 {0xf6, '6',   0, 0},    /* cursor right */
                  {'+', '+',   0, 0},    /* gray plus */
                 {0xfe, '1',   0, 0},    /* End */
      /* 50h */  {0xf8, '2',   0, 0},    /* cursor down */
                 {0xfa, '3',   0, 0},    /* Pg Dn */
                 {0xfd, '0',   0, 0},    /* Ins */
                 {0xfc, '.',   0, 0},    /* Del */
                 {0,      0,   0, 0},
                 {0,      0,   0, 0},
                 {0,      0,   0, 0},
                 {0,      0,   0, 0},
      /* 58h */  {0,      0,   0, 0},
                 {0,      0,   0, 0},
                 {0,      0,   0, 0},
                 {0,      0,   0, 0},    /* left Windows key */
                 {0,      0,   0, 0},    /* right Windows key */
                 {0,      0,   0, 0}};   /* pop-up menu key */

static char KbdConvertKey(u32 key_dword)
{
   u8  col;
   u8  scan_code = (u8)key_dword;
   u16  scan_codew = (u16)key_dword;
   int   num, caps, shift;
   // The NUM, etc macros below use "ShiftFlags" -- that's why we create
   // this variable here (otherwise, it would be necessary to pass a
   // parameter to the macro, which undercuts the simplicity). Don't worry
   // about masking other bits such as scan codes.
   u32 ShiftFlags = key_dword;

   // We don't care about key releases. Return NUL char.
   if((scan_code & brk))
      return('\0');

   // These make the checks below easier -- allow adding to check if
   // two keys are pressed or just one.
   num = (NUM ? 1 : 0);
   caps = (CAPS ? 1 : 0);
   shift = (SHIFT ? 1 : 0);

   if(ALT)                         col = 3;
   else if(CTRL)                   col = 2;

   // For gray cursor keys (arrows, home, etc) and keys in keypad:
   // 1. Gray keys: use column 0 -- always interpret as cursor keys.
   //    (We know it's a gray key because high byte of scan code is e0.)
   // 2. Keypad keys: if NumLock on or Shift, use col 1 (numbers),
   //    but if both on, they "cancel" each other -- use col 0.
   else if((scan_code >= 0x47) && (scan_code <= 0x53))

      if (scan_codew & 0xe000)     col = 0;
      else if ((num + shift) & 1)  col = 1;
      else                         col = 0;

   // For letter keys, if CapsLock on or Shift, use col 1 (upper case),
   // but if both on, they "cancel" each other -- use col 0.
   else if ((scan_code >= 0x10 && scan_code <= 0x19) ||
            (scan_code >= 0x1e && scan_code <= 0x26) ||
            (scan_code >= 0x2c && scan_code <= 0x32))

      if ((caps + shift) & 1)      col = 1;
      else                         col = 0;

   else if (shift)                 col = 1;
   else                            col = 0;

   return (smxKeyTable[scan_code][col]);
}


static void CheckKBDMsg()
{
    unsigned char key;
    char buf[2];
    if(g_getKBDMsg == 1)
    {
        switch(g_KeyCode)
        {
        case SB_KBD_FL_SCROLL:
            USBHPutString("VK_SCROLL");
            break;
        case SB_KBD_FL_CAPS:
            USBHPutString("VK_CAPITAL");
            break;
        case SB_KBD_FL_NUM:
            USBHPutString("VK_NUMLOCK");
            break;
        case SB_KBD_FL_INS:
            USBHPutString("VK_INSERT");
            break;
        case SB_KBD_FL_ALT:
            USBHPutString("VK_ALT");
            break;
        case SB_KBD_FL_CTRL:
            USBHPutString("VK_CONTROL");
            break;
        case SB_KBD_FL_RSHIFT:
            USBHPutString("VK_RIGHT_SHIFT");
            break;
        case SB_KBD_FL_LSHIFT:
            USBHPutString("VK_LEFT_SHIFT");
            break;
        default:
            if ((key = KbdConvertKey(g_KeyCode)) != '\0')
            {
                buf[0] = key;
                buf[1] = 0;
                USBHPutString(buf);
            }
            break;
        }
        g_getKBDMsg = 0;
    }
}
#endif

#if DEMO_STORAGE
FILEHANDLE fp;
#define SECTORS_PER_ACCESS 8
// static void TestMassStorage(void)
// {
// 	//USBHPutString("TestMassStorage\r\n");
//     static unsigned long int i = 0;
//     printf("sys_devstatus = %d\r\n", sfs_devstatus(0));
//     if(SFS_DEVICE_MOUNTED == sfs_devstatus(0))
//     {
//     	printf("SFS_DEVICE_MOUNTED\r\n");

//         char buf[64];
//         char temp[16];
//         if (!fp) {
//             fp = sfs_fopen("a:\\speed5.txt", "wb");

//             strcpy(buf, "Test Data ");
//             _ultoa(i++, temp, 10);
//             strcat(buf, temp);
//             sfs_fwrite(buf, strlen(buf), 1, fp);
//             sfs_fclose(fp);
//             strcpy(g_TempBuf, "Write File ");
//             _ultoa(i, g_TempBuf1, 10);
//             strcat(g_TempBuf, g_TempBuf1);
//             strcat(g_TempBuf, " Done");
//             USBHPutString(g_TempBuf);
//         }
//     }
// #ifdef SMXFS
//     static u32 i = 0;
//     u32 SectorSize;
//     static u8 * buf = NULL;

//     if(su_MStorMediaInserted(0, 0))
//     {
//         if(buf == NULL)
//         {
//             SectorSize = (SECTORS_PER_ACCESS*su_MStorSectorSize(0, 0));
//             buf = (u8 *)malloc((uint)SectorSize);
//             if(buf == NULL)
//             {
//                 return;
//             }
//         }

//         strcpy(g_TempBuf, "Testing Sector ");
//         _ultoa(i, g_TempBuf1, 10);
//         strcat(g_TempBuf, g_TempBuf1);
//         USBHPutString(g_TempBuf);
//         if(SU_MS_E_OK != su_MStorIO(0, 0, buf, i, SECTORS_PER_ACCESS, 1))
//         {
//             USBHPutString("USB Storage Test Failed");
//             i = 0;
//             free(buf);
//             buf = NULL;

//         }
//         else
//         {
//             i += SECTORS_PER_ACCESS;
//             if(i >= su_MStorSectorNum(0, 0))
//                 i = 0;
//         }
//     }
// #else

// #endif
// }



static int usb_readData(char *fileName, uint8_t *pData, int len)
{
	FILEHANDLE pFile = NULL;
	int uFLen,readLen,remainLen,offset = 0;
	int baseLen = 1024*1000;

	if((NULL == fileName) || (NULL == pData) || (0 == len)){
		printf("input illegal \n");
		return -1;
	}

	if(SFS_DEVICE_MOUNTED != sfs_devstatus(0)){
		printf("usb device not mounted \n");
		return -1;
	}

	if (NULL == (pFile = sfs_fopen(fileName, "rb"))){
		printf("File read open failed \n");
        return -1;
	}

	if (sfs_fseek(pFile, 0, SFS_SEEK_SET)){
		printf("File seek error \n");
        return -1;
	}

	uFLen = sfs_filelength(fileName);
	printf("file len: %d \n", uFLen);

	remainLen = len >= uFLen ? uFLen : len;
	printf("read begin : \n");
	while(remainLen)
	{
		readLen = remainLen > baseLen ? baseLen : remainLen;
		sfs_fread(pData+offset, readLen, 1, pFile);

		sfs_fseek(pFile, 0, SFS_SEEK_CUR);

		remainLen -= readLen;
		offset += readLen;
	}
	printf("read over ! \n");
	sfs_fclose(pFile);

	return offset;
}

static int usb_readLine(FILEHANDLE pFile, uint8_t *pData, int len)
{
	int i = 0;
	int offset = 0;
	if((NULL == pFile) || (NULL == pData) || (0 == len)){
		printf("input illegal \n");
		return -1;
	}

    printf("[lf] : len %d \n", len);

	for(i=0;i<len;i++)
	{
		if(sfs_feof(pFile))
			break;

		sfs_fread(pData+offset, 1, 1, pFile);
		printf("[lf]:%d ,%c ,offset %d ,len %d \n", i ,*(pData+offset) , offset , len);
		offset += 1;
		sfs_fseek(pFile, 0, SFS_SEEK_CUR);

		// if(0 == memcmp(pData+offset,0x0A,1)){
        //     printf("line end \n");
		// 	break;
		// }
	}

	return offset;
}

static int usb_writeData(char *fileName, uint8_t *pData, int len)
{
	FILEHANDLE pFile = NULL;
	int offset = 0;

	if((NULL == fileName) || (NULL == pData) || (0 == len)){
		printf("input illegal \n");
		return -1;
	}

	if(SFS_DEVICE_MOUNTED != sfs_devstatus(0)){
		printf("usb device not mounted \n");
		return -1;
	}

	if (NULL == (pFile = sfs_fopen(fileName, "wb"))){
		printf("File write open failed \n");
        return -1;
	}

	if (sfs_fseek(pFile, 0, SFS_SEEK_SET)){
		printf("File seek error \n");
        return -1;
	}

    if (sfs_fwrite(pData, len, 1, pFile) < 0){
		printf("File write error \n");
        return -1;
    }

	printf("write over ! \n");
	sfs_fclose(pFile);

	return offset;
}

char fileName1[20] = {"a:\\ir.raw"};
char fileName2[20] = {"a:\\rgb.raw"};
#if 0
static int usb_readCfgFile(char *fileName)
{
	char readData[20];
	int i,len = 0;
    int ret = 0;
	int updateFlag = 0;
	FILEHANDLE pFile = NULL;

	if(NULL == fileName){
		printf("input illegal \n");
		return -1;
	}

	if(SFS_DEVICE_MOUNTED != sfs_devstatus(0)){
		printf("usb device not mounted \n");
		return -1;
	}

	if (NULL == (pFile = sfs_fopen(fileName, "rb+"))){
		printf("File read open failed \n");
	}

	if (sfs_fseek(pFile, 0, SFS_SEEK_SET)){
		printf("File seek error \n");
	}

	len = usb_readLine(pFile,(uint8_t *)readData,20);
	printf("len %d %d %d %d \n", len, strlen("USB_UPDATE"), sizeof("USB_UPDATE"), strlen("YES"));
	for(i=0;i<len;i++)
	{
		if(0 == memcmp(readData+i,"USB_UPDATE",strlen("USB_UPDATE")))
		{
			printf("usb update: \n");
			updateFlag = 1;
		}

		if(1 == updateFlag){
			if(0 == memcmp(readData+i,"YES",strlen("YES"))){
				printf("usb update now. \n");
                ret = 1;
				//usb_readData(fileName1,0x800000,0x38400);
			}else if(0 == memcmp(readData+i,"NO",strlen("NO"))){
				printf("usb not update \n");
			}
		}
	}

    if(pFile) {
        sfs_fclose(pFile);
    }

	return ret;
}
#endif

// 0 : yes
// 1 : no
// 2 : not fund
static int usb_readCfgInfo(char *fileName, char *keyWords)
{
	int i,len = 0;
    int ret = 2;
    int updateFlag = 0;
    int maxReadLineLen = 20;
    char readData[maxReadLineLen];
	FILEHANDLE pFile = NULL;

	if(NULL == fileName){
		printf("input illegal \n");
		return -1;
	}

	if(SFS_DEVICE_MOUNTED != sfs_devstatus(0)){
		printf("usb device not mounted \n");
		return -1;
	}

	if (NULL == (pFile = sfs_fopen(fileName, "rb+"))){
		printf("File read open failed \n");
        return -1;
	}

	if (sfs_fseek(pFile, 0, SFS_SEEK_SET)){
		printf("File seek error \n");
        return -1;
	}

    while(!sfs_feof(pFile))
    {
        len = usb_readLine(pFile,(uint8_t *)readData,maxReadLineLen);
        printf("[lf]:len %d ,key word : %s, len %d \n", len, keyWords,strlen(keyWords));

        for(i=0;i<len;i++)
        {
            if(0 == memcmp(readData+i,keyWords,strlen(keyWords)))
            {
                printf("[lf]:get keyWords \n");
                updateFlag = 1;
            }

            if(1 == updateFlag){
                if(0 == memcmp(readData+i,"YES",strlen("YES"))){
                    printf("[lf]:key worsd : YES. \n");
                    ret = 0;
                    break;
                }else if(0 == memcmp(readData+i,"NO",strlen("NO"))){
                    printf("[lf]:key words : NO \n");
                    ret = 1;
                    break;
                }
            }
        }

        sfs_fseek(pFile, 0, SFS_SEEK_CUR);

        if((0 == ret) || (1 == ret))
            break;
    }

    if(pFile) {
        sfs_fclose(pFile);
    }

	return ret;
}

#include "data_move.h"
static int usb_update_bin_flag = 0;
static void TestMassReader(void)
{
    int ret = 0;
    int offset = 0;
    char fileName[30] = {"a:\\usbCfg.txt"};
    char binName[30] = {"a:\\test.bin"};

    if(1 == usb_update_bin_flag)
        return;

	//ret = usb_readCfgFile(fileName);
    ret = usb_readCfgInfo(fileName, "USB_UPDATE");
    printf("[lf]:ret %d \n", ret);
    if(0 == ret)
    {
        printf("read bin ... \n");
        offset = usb_readData(binName,(uint8_t *)0x7000000,0xb00000);
        printf("update bin ...%d \n", offset);
        qspi_flash_write(QSPI_START_BASEADDR,(uint8_t *)0x7000000,offset);
        usb_update_bin_flag = 1;
        printf("update done !!!!! \n");
    }
}


void fw_update(void)
{
    int ret = 0;
    int offset = 0;
    char fileName[30] = {"a:\\usbCfg.txt"};
    char binName[30] = {"a:\\update_flash_firmware.bin"};

    if(1 == usb_update_bin_flag)
    {
        printf("Firmware update success, please reset update again \r\n");
        return;
    }   

	//ret = usb_readCfgFile(fileName);
    ret = usb_readCfgInfo(fileName, "USB_UPDATE");
    printf("[lf]:ret %d \n", ret);
    if(0 == ret)
    {
        printf("read bin ... \n");
        offset = usb_readData(binName,(uint8_t *)0x7000000,0x1000000);
        if(offset==-1) 
		{
			printf("file error  \n");
			return;
		}
        printf("update bin ...%d \n", offset);
        qspi_flash_write(QSPI_START_BASEADDR,(uint8_t *)0x7000000,0x1000000);
        printf("update done !!!!! \n");
        aos_msleep(5);
        memcpy_with_sleep((uint8_t *)0x7000000, (uint8_t *)QSPI_START_BASEADDR, offset);
        printf("read update complate !!!!! \n");
        uint32_t g_ulIfvusbupdate = false;
        ret = aos_kv_set(IFV_USB_FIRMWARE_ENABLE, &g_ulIfvusbupdate, sizeof(g_ulIfvusbupdate), 1);
        if (ret != 0) 
        {
            printf("Failed to disable usb update\r\n");
        }
        usb_update_bin_flag = 1;
    }

}

/*保存ir图片的命名规范
* irA_B_C_D.raw
* A:    序号（从0开始）
* B:    摄像头的序号（0 or 1）
* C：   注册or识别（1 or 2）
* D：   算法返回的result
* example: ir0_0_1_0.raw
*/
#define USB_PIC_SAVE_PATH	"usbPicSave"
void usb_save_double_ir_pic(int32_t algoType, int32_t result, uint8_t *irData_0, int32_t dataLen_0, uint8_t *irData_1, int32_t dataLen_1)
{
    int32_t ret = -1;
    int32_t num = 0;
    int32_t tmp = 0;
    char fileName[64] = {0};
    char tmpPath[64] = {0};
    FILEINFO* fileinfo = NULL;
    int pFile;

	printf("su_CheckRoothubStatus\n");
	su_CheckRoothubStatus();
    if(SFS_DEVICE_MOUNTED != sfs_devstatus(0))
    {
        printf("%s:usb device not mount\n", __func__);
        return;
    }

    //mkdir
    snprintf(tmpPath, sizeof(tmpPath), "a:\\%s", USB_PIC_SAVE_PATH);    
    if(sfs_mkdir(tmpPath) != 1)
    {
        printf("%s:mkdir a:\\%s error\n", __func__, USB_PIC_SAVE_PATH);
        return;
    }
    
    //get new img num
    memset(tmpPath, 0, sizeof(tmpPath));
    snprintf(tmpPath, sizeof(tmpPath), "a:\\%s\\ir*.raw", USB_PIC_SAVE_PATH);
    pFile = sfs_findfirst(tmpPath, fileinfo);    
    if(pFile != -1)
    {
        do
        {
            sscanf((char *)fileinfo->name, "ir%d_", &tmp);
            if(tmp >= num)
                num = tmp + 1;
            pFile = sfs_findnext(pFile, fileinfo);
        }while(pFile != -1);
    }
    else
    {
        num = 0;
    }
    
    //save ir0
    snprintf(fileName, sizeof(fileName), "a:\\%s\\ir%d_0_%d_%d.raw", 
                USB_PIC_SAVE_PATH, num, algoType, result);   
    ret = usb_writeData(fileName, irData_0, dataLen_0);
    if(ret < 0)
        return;
    printf("[%s] save success\n", fileName);

    //save ir1
    memset(fileName, 0 , sizeof(fileName));
    snprintf(fileName, sizeof(fileName), "a:\\%s\\ir%d_1_%d_%d.raw", 
                USB_PIC_SAVE_PATH, num, algoType, result);    
    ret = usb_writeData(fileName, irData_1, dataLen_1);
    if(ret < 0)
        return;
    printf("[%s] save success\n", fileName);

    return;
}



#endif

/* The printer demo will print some information to a USB printer.
   You should have an HP PCL-compatible printer to get the correct output.
   Otherwise the output will be garbage or it may have no response at all.
*/

#if DEMO_PRINTER
#if 1
//#include "prnhpijs.h" /* HP IJS */
#include "prnhppcl.h" /* HP PCL */
//#include "prnhpdj.h"  /* HP DJ */
#endif
#define PRINTER_ID 0

static void PrintOut(void)
{
    static int Done = 0;
    if(su_PrnInserted(PRINTER_ID) && !Done)
    {
#if 1
        int i;
        u8 * pData = (u8 *)&szPrnData[0];
        int size = sizeof(szPrnData);

        u8 status = su_PrnStatus(PRINTER_ID);
        if(status&SU_PRN_STATUS_PAPEREMPTY)
            USBHPutString("PaperEmpty");
        if(status&SU_PRN_STATUS_SELECTED)
            USBHPutString("Selected");
        if(status&SU_PRN_STATUS_NOERROR)
            USBHPutString("NoError");

        USBHPutString("Outputing Printer Data:");

        for(i = 0; i < size/1024; i++)
        {
            su_PrnWrite(PRINTER_ID, pData,1024);
            //printf(".");
            pData += 1024;

        }
        su_PrnWrite(PRINTER_ID, pData,size-i*1024);
        //printf("Done\n");
        Done = 1;
#else
        int len;
        static int i = 0;
        u8 data[7] = {0x0d, 0x0a, 0x55, 0x45, 0x0d, 0x0a};
        u8 * pData = (u8 *)malloc(2048);
        len = su_PrnRead(PRINTER_ID, pData, 2048);
        i++;
        if(len == 0)
        {
            USBHPutString("No  Response");
        }
        if(0 == (i % 50))
        {
            su_PrnWrite(PRINTER_ID, &data[0], 7);
            len = su_PrnRead(PRINTER_ID, pData, 2048);
            if(len > 0)
            {
                pData[len] = 0;
                //printf((char *)pData);
                USBHPutString("Get Response");
            }
        }

        free(pData);
#endif
    }
}

#endif

#if DEMO_CDCACM
static int g_CDCACMConnected = 0;

static void CDCACMHandle(uint iID, uint iType, u16 wParam)
{
    (void)iID;
    g_TempBuf1[0] = 0;
    switch(iType)
    {
    case SU_CDCACM_CONNECT_CHANGED:
        strcpy(g_TempBuf, "Connect Status: ");
        _ultoa(wParam, g_TempBuf1, 10);
        g_CDCACMConnected = wParam;
        break;
    case SU_CDCACM_LINE_STATE_CHANGED:
        strcpy(g_TempBuf, "LineState: 0x");
        _ultoa(wParam, g_TempBuf1, 10);
        if(wParam & SU_CDCACM_LINE_IN_DCD)
        {
            strcat(g_TempBuf1, " Connected");
            g_CDCACMConnected = 1;
        }
        else if(!(wParam & SU_CDCACM_LINE_IN_DCD))
        {
            if(g_CDCACMConnected)
            {
                strcat(g_TempBuf1, " Disconnected");
                g_CDCACMConnected = 0;
            }
        }
        
        break;
    case SU_CDCACM_RESPONSE_READY:
        strcpy(g_TempBuf, "Response Ready");
        break;
    }
    strcat(g_TempBuf, g_TempBuf1);
    USBHPutString(g_TempBuf);
}

static int SendATCmd(char *pszCmd)
{
    int len;
    char szBuf[40];
    strcpy(szBuf, pszCmd);
    strcat(szBuf, "\r");
    len = strlen(szBuf);
    if(len == su_CDCACMWrite(0, (u8 *)szBuf, len))
        return 1;
    else
        return 0;
}

static int GetResponse(char *pszResponse, int size, uint timeout)
{
    int i, j;
    int iSize;
    char szResponse[256];

    iSize = su_CDCACMRead(0, (u8 *)szResponse, 255, timeout);
    if(iSize > 0)
    {
        szResponse[iSize] = 0;
        for(i = 0, j = 0; i < iSize, j < size - 1; i++)
        {
            if(szResponse[i] != '\r' && szResponse[i] != '\n')
                pszResponse[j++] = szResponse[i];
            else
                pszResponse[j++] = ' ';
        }
        pszResponse[j] = 0;
        
    }
    return iSize;
}

static void TestATCmd(char *pszCmd)
{
    char szResponse[128];
    if(SendATCmd(pszCmd))
    {
        if(0 == GetResponse(szResponse, 128, 3000))
        {
            strcpy(szResponse, pszCmd);
            strcat(szResponse, " Response Failed");
        }
        USBHPutString(szResponse);
    }
    else
    {
        USBHPutString("Send AT Cmd Failed");
    }
    
}

static void QueryModem()
{
    TestATCmd("ATQ0V1E0");
    TestATCmd("AT+FCLASS=?");
    TestATCmd("ATI1");
    TestATCmd("ATI2");
    TestATCmd("ATI3");
    TestATCmd("ATI4");
    TestATCmd("ATI5");
    TestATCmd("ATI6");
}

static void TestModem(void)
{
    static int Opened = 0;

    if(su_CDCACMInserted(0))
    {
        if(!Opened)
        {
            USBHPutString("Try to Open USB Modem");
            Opened = (su_CDCACMOpen(0) == 0);
        }
        if(Opened)
        {
            QueryModem();
        }
        else
        {
            USBHPutString("Open USB Modem failed");
        }
    }
    else
    {
        //USBHPutString("No USB Modem detected");
    }

}
#endif /* DEMO_CDCACM */

#if DEMO_UF8000
/* Demo Panasonic UF8000 Fax Machine driver
*/

static void TestUF8000(void)
{
    u8 szDataBuf[256];
    int len;
    u8 szOpenLinkCmd [] = {0x02,0x00,0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf7};
    u8 szOpenLinkResp[] = {0x01,0x00,0x0a,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0xf2};

    //u8 szStartSessionCmd[] = {0x02,0x01,0x18,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x43,0x46,0x50,0x31,0x2e,0x34,0x35,0x2d,0x33,0x2e,0x39,0x30,0x04,0x00,0x39};
    //u8 szStartSessionResp[] = {0x01,0x01,0x16,0x00,0x02,0x00,0x01,0x00,0x00,0x00,0x0e,0x00,0x43,0x46,0x50,0x31,0x2e,0x35,0x30,0x20,0x20,0x20,0x20,0x20,0x04,0x00,0x97};

    u8 szLocalCapCmd [] = {0x02,0x02,0x08,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf2};
    u8 szLocalCapResp [] = {0x01,0x02,0x72,0x00,0x04,0x00,0x01,0x80,0x00,0x00,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,
                       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3,0x63,
                       0xf0,0x00,0x04,0x00,0x03,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,
                       0x00,0x1a,0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,
                       0x08,0x00,0x09,0x00,0x0b,0x00,0x0e,0x00,0x0f,0x00,0x10,0x00,0x11,0x00,0x12,0x00,0x13,
                       0x00,0x14,0x00,0x15,0x00,0x16,0x00,0x17,0x00,0x1a,0x00,0x1b,0x00,0x25,0x00,0x26,0x00,
                       0x27,0x00,0x28,0x00,0x0a,0x41,0x41,0x56,0x32,0x31,0x37,0x30,0x30,0x41,0x55,0x00,0x0b};

    u8 szEndSessionCmd[] = {0x02,0x03,0x08,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf2};
    u8 szEndSessionResp[] = {0x01,0x03,0x08,0x00,0x03,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0xf1};

    if(su_UF8000Inserted(0))
    {
        su_UF8000SendData(0, szOpenLinkCmd, sizeof(szOpenLinkCmd));
        len = su_UF8000QuiryDataLen(0);
        su_UF8000RecvData(0, szDataBuf, len);
        if(memcmp(szDataBuf, szOpenLinkResp, len) != 0)
            USBHPutString("Open Link Command check failed");
        //su_UF8000SendData(0, szStartSessionCmd, sizeof(szStartSessionCmd));
        //len = su_UF8000QuiryDataLen(0);
        //su_UF8000RecvData(0, szDataBuf, len);
        //if(memcmp(szDataBuf, szStartSessionResp, len) != 0)
        //    printf("Start Session Command check failed\n");
        su_UF8000SendData(0, szLocalCapCmd, sizeof(szLocalCapCmd));
        len = su_UF8000QuiryDataLen(0);
        su_UF8000RecvData(0, szDataBuf, len);
        if(memcmp(szDataBuf, szLocalCapResp, len) != 0)
            USBHPutString("Local Capabilities Command check failed");
        su_UF8000SendData(0, szEndSessionCmd, sizeof(szEndSessionCmd));
        len = su_UF8000QuiryDataLen(0);
        su_UF8000RecvData(0, szDataBuf, len);
        if(memcmp(szDataBuf, szEndSessionResp, len) != 0)
            USBHPutString("End Session Command check failed");
   }

}
#endif /* DEMO_UF8000 */

#if DEMO_FTDI232
static void FTDI232Receive(void)
{
    char szBuf[64];
    char szBuf1[16];

        if(su_FTDIInserted(0))
        {
            /* we need to open it first */
            if(!Opened)
            {
                Opened = (su_FTDIOpen(0) == 0);
            }
            if(Opened)
            {
                /* if we got something, just send them back */
                g_iFTDI232Received = su_FTDIReadData(0, g_pFTDI232Buf, 256);
                if(g_iFTDI232Received > 0)
                {
                    /* signal another task to send it */
                    usb_ftdi232_data_ready = 1;
                    strcpy(g_TempBuf, "Received Data: ");
                    _ultoa(g_iFTDI232Received, g_TempBuf1, 10);
                    strcat(g_TempBuf, g_TempBuf1);
                    USBHPutString(g_TempBuf);
                }
            }
        }
        else
        {
            Opened = 0;
        }

}

static void FTDI232Send(void)
{
    u8 bModemStatus;
    u8 bLineStatus;

        /* wakeup when we get the signal then send the data back */
    if(usb_ftdi232_data_ready)
    {
        su_FTDIGetStatus(0, &bModemStatus, &bLineStatus);
        if(bLineStatus & (SU_FTDI232_OE|SU_FTDI232_PE|SU_FTDI232_FE|SU_FTDI232_BI|SU_FTDI232_FIFOE))
        {
            USBHPutString("Error Occured");
        }
        su_FTDIWriteData(0, g_pFTDI232Buf, g_iFTDI232Received);
        g_iFTDI232Received = 0;
        usb_ftdi232_data_ready = 0;
    }

}
#endif /* DEMO_FTDI232 */

#if DEMO_PL2303
static int usb_pl2303_data_ready = 0;
static int g_iPL2303Opened = 0;
static int g_iPL2303Received = 0;

void PL2303Handle(uint iID, u16 wNewLineState)
{
    char Buf1[32];
    char Buf2[16];
    strcpy(Buf1, "LineState: 0x");
    _ultoa(wNewLineState, Buf2, 16);
    strcat(Buf1, Buf2);
    USBHPutString(Buf1);
}

static void PL2303Receive(void)
{

    if(su_PL2303Inserted(0))
    {
        /* we need to open it first */
        if(!g_iPL2303Opened)
        {
            g_iPL2303Opened = (su_PL2303Open(0) == 0);
        }
        if(g_iPL2303Opened)
        {
            /* if we got something, just send them back */
            g_iPL2303Received = su_PL2303ReadData(0, g_pPL2303Buf, SU_PL2303_MTU, 100);
            if(g_iPL2303Received > 0)
            {
                /* signal another task to send it */
                usb_pl2303_data_ready = 1;
                strcpy(g_TempBuf, "Received Data: ");
                _ultoa(g_iPL2303Received, g_TempBuf1, 10);
                strcat(g_TempBuf, g_TempBuf1);
                USBHPutString(g_TempBuf);
            }
        }
    }
    else
    {
        g_iPL2303Opened = 0;
    }
}

static void PL2303Send(void)
{
    /* wakeup when we get the signal then send the data back */
    if(usb_pl2303_data_ready)
    {
        su_PL2303WriteData(0, g_pPL2303Buf, g_iPL2303Received);
        g_iPL2303Received = 0;
        usb_pl2303_data_ready = 0;
    }

}
#endif /* DEMO_PL2303 */

#if DEMO_HID
/* Demo HID driver 
   This demo will try to get the report of the HID device and display it.
   
*/
static SU_HID_USAGE_INFO g_hidUsageInfo;
static int g_getHIDMsg = 0;
static s32 g_HIDData;
static void USBHIDHandler(uint iID, SU_HID_FIELD_INFO *pFieldInfo, SU_HID_USAGE_INFO *pUsageInfo, s32 data)
{
    (void)iID;
    (void)pFieldInfo;
    g_HIDData = data;
    memcpy(&g_hidUsageInfo,  pUsageInfo, sizeof(SU_HID_USAGE_INFO));
    g_getHIDMsg = 1;
}


static void CheckHIDMsg(void)
{
    char *p;
    char num[16];
    char buf[128];
    if(g_getHIDMsg == 1)
    {
    /* get the type */
    strcpy(buf, "T:");
    switch(g_hidUsageInfo.type)
    {
    case SU_HID_TYPE_KEY:
        p = "key";
        break;
    case SU_HID_TYPE_REL:
        p = "Relative";
        break;
    case SU_HID_TYPE_ABS:
        p = "Absolute";
        break;
    case SU_HID_TYPE_MSC:
        p = "misc";
        break;
    case SU_HID_TYPE_LED:
        p = "led";
        break;
    case SU_HID_TYPE_SOUND:
        p = "sound";
        break;
    default:
        p = "unsup";
        break;
    }
    /* get the code */
    strcat(buf, p);
    strcat(buf, " C:");
    sprintf(num, "%d", g_hidUsageInfo.code);
    strcat(buf, num);
    /* get the data */
    strcat(buf, " D:");
    sprintf(num, "%d", g_HIDData);
    strcat(buf, num);
    USBHPutString(buf);
    g_getHIDMsg = 0;
    }
}
#endif /* DEMO_HID */

#if DEMO_SERIAL
/* Demo Serial driver
   we will try to send some data to the device and then read back and
   compare if it is the same. we assume on the device side some application
   will send back all the data it received to the host side, just like what we
   do in the smxUSBD serial driver.
*/
#define SERIAL_PACKET_SIZE 64 /* how many data we will send for each packet */
/* when line state is changed, this call back function will be called */
void SerialHandle(uint iID, u16 wNewLineState)
{
    strcpy(g_TempBuf, "LineState: 0x");
    _ultoa(wNewLineState, g_TempBuf1, 10);
    strcat(g_TempBuf, g_TempBuf1);
    USBHPutString(g_TempBuf);
}

void SerialCheck(void)
{
    int i = 'A' - 1;
    u8 * buf1 = NULL;
    u8 * buf2 = NULL;
    static int Opened = 0;

    if(su_SerialInserted(0))
    {
        buf1 = (u8 *)malloc( 2*SERIAL_PACKET_SIZE );
        if(buf1 == NULL)
        {
             USBHPutString("NoMemoryForPacketBuffer");
             return;
        }
        buf2 = buf1 + SERIAL_PACKET_SIZE;
        /* we need to open the serial device first */
        if(!Opened)
        {
            sb_OS_WAIT_MSEC_MT(1000);
            Opened = (su_SerialOpen(0) == 0);
        }
        if(Opened && buf1)
        {
            /* then write the data to the device */
            i++;
            if(i > 'z')
                i = 'A';
            memset(buf1, i, SERIAL_PACKET_SIZE);
            su_SerialWrite(0, buf1, SERIAL_PACKET_SIZE);
            if(buf2 && su_SerialInserted(0))
            {
                /* finally try to read the data back */
                if(SERIAL_PACKET_SIZE == su_SerialRead(0, buf2, SERIAL_PACKET_SIZE))
                {
                    /* compare it to check if the sent and received is the same */
                    if(memcmp(buf1, buf2, SERIAL_PACKET_SIZE))
                    {
                        USBHPutString("SerialDataNotMatch");
                    }
                    else
                    {
                        USBHPutString("Testing Data, No error");
                    }
                }
                else
                {
                    USBHPutString("SerialDataTooShort");
                }
            }
        }
        if(buf1)
            free(buf1);
    }

}
#endif /* DEMO_SERIAL */

#if DEMO_VIDEO
#if VIDEO_DISPLAY

static int iYUVFormat;

static void YUV420toRGB565(u8 *yuvs, int width, int height, u8 *rgbs) 
{
    //the end of the luminance data
    int lumEnd = width * height;
    //points to the next luminance value pair
    int lumPtr = 0;
    //points to the next chromiance value pair
    int chrPtr = lumEnd;
    //points to the next byte output pair of RGB565 value
    int outPtr = 0;
    //the end of the current luminance scanline
    int lineEnd = width;
    int R, G, B;
    int Y1; 
    int Y2; 
    int Cr; 
    int Cb;

    while (width > 0) 
    {

        //skip back to the start of the chromiance values when necessary
        if (lumPtr == lineEnd) 
        {
            if (lumPtr == lumEnd) 
                break; //we've reached the end
            //division here is a bit expensive, but's only done once per scanline
            chrPtr = lumEnd + ((lumPtr  >> 1) / width) * width;
            lineEnd += width;
        }

        //read the luminance and chromiance values
        Y1 = yuvs[lumPtr++] & 0xff; 
        Y2 = yuvs[lumPtr++] & 0xff; 
        Cr = (yuvs[chrPtr++] & 0xff)-128; 
        Cb = (yuvs[chrPtr++] & 0xff)-128;

        //generate first RGB components
        B = Y1 + ((454 * Cb) >> 8);
        if(B < 0) B = 0; else if(B > 255) B = 255; 
        G = Y1 - ((88 * Cb + 183 * Cr) >> 8); 
        if(G < 0) G = 0; else if(G > 255) G = 255; 
        R = Y1 + ((359 * Cr) >> 8); 
        if(R < 0) R = 0; else if(R > 255) R = 255; 
        //NOTE: this assume little-endian encoding
        rgbs[outPtr++]  = (u8) ((((G & 0x3c) << 3) | (B >> 3))&0xFF);
        rgbs[outPtr++]  = (u8) (((R & 0xf8) | (G >> 5))&0xFF);

        //generate second RGB components
        B = Y2 + ((454 * Cb) >> 8);
        if(B < 0) B = 0; else if(B > 255) B = 255; 
        G = Y2 - ((88 * Cb + 183 * Cr) >> 8); 
        if(G < 0) G = 0; else if(G > 255) G = 255; 
        R = Y2 + ((359 * Cr) >> 8); 
        if(R < 0) R = 0; else if(R > 255) R = 255; 
        //NOTE: this assume little-endian encoding
        rgbs[outPtr++]  = (u8) ((((G & 0x3c) << 3) | (B >> 3))&0xFF);
        rgbs[outPtr++]  = (u8) (((R & 0xf8) | (G >> 5))&0xFF);
    }
}

static void YUV422toRGB565(u8 *yuvs, int width, int height, u8 *rgbs) 
{
    //the end of the luminance data
    int lumEnd = 2 * width * height;
    //points to the next luminance value pair
    int lumPtr = 0;
    //points to the next byte output pair of RGB565 value
    int outPtr = 0;
    int R, G, B;
    int Y1; 
    int Y2; 
    int Cr; 
    int Cb;

    while (lumPtr < lumEnd) 
    {

        //read the luminance and chromiance values
        Y1 = yuvs[lumPtr++]-16;
        Cb = yuvs[lumPtr++]-128;
        Y2 = yuvs[lumPtr++]-16;
        Cr = yuvs[lumPtr++]-128;


        //generate first RGB components
        B = Y1 + ((454 * Cb) >> 8);
        G = Y1 - ((88 * Cb + 183 * Cr) >> 8); 
        R = Y1 + ((359 * Cr) >> 8); 
        
        if(B < 0) B = 0; else if(B > 255) B = 255; 
        if(G < 0) G = 0; else if(G > 255) G = 255; 
        if(R < 0) R = 0; else if(R > 255) R = 255; 

        //NOTE: this assume little-endian encoding
        rgbs[outPtr++]  = (u8) ((((G & 0x3c) << 3) | (B >> 3))&0xFF);
        rgbs[outPtr++]  = (u8) (((R & 0xf8) | (G >> 5))&0xFF);

        //generate second RGB components
        B = Y2 + ((454 * Cb) >> 8);
        G = Y2 - ((88 * Cb + 183 * Cr) >> 8); 
        R = Y2 + ((359 * Cr) >> 8); 
        
        if(B < 0) B = 0; else if(B > 255) B = 255; 
        if(G < 0) G = 0; else if(G > 255) G = 255; 
        if(R < 0) R = 0; else if(R > 255) R = 255; 
        
        //NOTE: this assume little-endian encoding
        rgbs[outPtr++]  = (u8) ((((G & 0x3c) << 3) | (B >> 3))&0xFF);
        rgbs[outPtr++]  = (u8) (((R & 0xf8) | (G >> 5))&0xFF);
    }
}

void VideoDisplay(void)
{
    if(g_pFrameBuffer)
    {
         if(iYUVFormat == SU_VIDEO_FORMAT_UNCOMPRESSED_YUV420)
             YUV420toRGB565(pCaptureBuffer[!g_iCurrentIndex], VIDEO_CAPTURE_WIDTH, VIDEO_CAPTURE_HEIGHT, g_pFrameBuffer);
         else if(iYUVFormat == SU_VIDEO_FORMAT_UNCOMPRESSED_YUV422)
             YUV422toRGB565(pCaptureBuffer[!g_iCurrentIndex], VIDEO_CAPTURE_WIDTH, VIDEO_CAPTURE_HEIGHT, g_pFrameBuffer);
    }
}
#endif

void TestVideo(void)
{
    int i, j;
    int ReadCount;
    int TotalCaptured;
    int CaptureFormatNum;
    int CaptureFrameIndex;
    int CaptureFrameIntervalIndex;
    int CaptureFormatMatched = 0;
    SU_VIDEO_CAPTURE_FORMAT CaptureFormat;
/*
    int StillSizeMatched = 0;
    int StillFormatNum;
    int StillFrameIndex;
    SU_VIDEO_STILL_IMAGE_FORMAT StillFormat;
*/
   
    if(su_VideoInserted(0))
    {
        /*
        StillFormatNum = su_VideoCameraGetStillImageFormatNum(0);
        for(i = 0; i < StillFormatNum && !StillSizeMatched; i++)
        {
            su_VideoCameraGetStillImageFormat(0, i, &StillFormat);
            if(StillFormat.iFormat == VIDEO_STILL_FORMAT)
            {
                for(StillFrameIndex = 0; StillFrameIndex < StillFormat.iPatternNum; StillFrameIndex++)
                {
                    if(StillFormat.wWidth[StillFrameIndex] == VIDEO_STILL_WIDTH && StillFormat.wHeight[StillFrameIndex] == VIDEO_STILL_HEIGHT)
                    {
                        StillSizeMatched = 1;
                        break;
                    }
                }
            }
        }
        if(StillSizeMatched)
        {
            su_VideoCameraSetStillImageFormat(0, StillFormat.iFormat,
                                          StillFormat.wWidth[StillFrameIndex],
                                          StillFormat.wHeight[StillFrameIndex]);
        }
        */
        CaptureFormatNum = su_VideoCameraGetCaptureFormatNum(0);
        for(i = 0; i < CaptureFormatNum && !CaptureFormatMatched; i++)
        {
            su_VideoCameraGetCaptureFormat(0, i, &CaptureFormat);
            if(CaptureFormat.iFormat == VIDEO_CAPTURE_FORMAT)
            {
                for(j = 0; j < CaptureFormat.bNumFrame && !CaptureFormatMatched; j++)
                {
                    if(CaptureFormat.Frame[j].wWidth == VIDEO_CAPTURE_WIDTH
                       && CaptureFormat.Frame[j].wHeight == VIDEO_CAPTURE_HEIGHT)
                    {
                        for(CaptureFrameIntervalIndex = 0; CaptureFrameIntervalIndex < CaptureFormat.Frame[j].iNumFrameInterval; CaptureFrameIntervalIndex++)
                        {
                            if(CaptureFormat.Frame[j].dwFrameInterval[CaptureFrameIntervalIndex] ==  VIDEO_CAPTURE_FRAME_INTERVAL)
                            {
                                CaptureFrameIndex = j;
                                CaptureFormatMatched = 1;
#if VIDEO_DISPLAY
                                iYUVFormat = CaptureFormat.iYUVFormat;
#endif
                                break;
                            }
                        }
                    }
                }
            }

        }
        if(CaptureFormatMatched)
        {
            u32 dwMaxVideoFrameSize, dwMaxPayloadBufferSize;
            su_VideoCameraSetCaptureFrame(0, CaptureFormat.iFormat,
                                          CaptureFormat.Frame[CaptureFrameIndex].wWidth,
                                          CaptureFormat.Frame[CaptureFrameIndex].wHeight,
                                          CaptureFormat.Frame[CaptureFrameIndex].dwFrameInterval[CaptureFrameIntervalIndex]);
            su_VideoCameraGetCaptureSize(0, &dwMaxVideoFrameSize, &dwMaxPayloadBufferSize);
            pCaptureBuffer[0] = (u8 *)malloc(dwMaxVideoFrameSize + dwMaxPayloadBufferSize);
            pCaptureBuffer[1] = (u8 *)malloc(dwMaxVideoFrameSize + dwMaxPayloadBufferSize);
            if(pCaptureBuffer[0] == NULL || pCaptureBuffer[1] == NULL)
            {
                USBHPutString("Can't allocate video capture buffer");
                return;
            }
            if(su_VideoCameraOpen(0) == 0)
            {
                BOOLEAN bNewFrame;
                uint    iNewFrameOffset;
                TotalCaptured = 0;
                USBHPutString("Capturing...");

                do
                {
                    ReadCount = su_VideoCameraCapture(0, pCaptureBuffer[g_iCurrentIndex] + TotalCaptured, dwMaxPayloadBufferSize, &bNewFrame, &iNewFrameOffset);
                    if(ReadCount < 0)
                    {
                        USBHPutString("Video camera capture failed");
                        break;
                    }
                    if(bNewFrame)
                    {
                        if(ReadCount >= iNewFrameOffset)
                        {
                            TotalCaptured += iNewFrameOffset;

                            g_iCurrentIndex = !g_iCurrentIndex;
#if VIDEO_DISPLAY
                            VideoDisplay();
#endif

                            if(ReadCount > iNewFrameOffset)
                                memcpy(pCaptureBuffer[g_iCurrentIndex], pCaptureBuffer[!g_iCurrentIndex] + TotalCaptured, ReadCount - iNewFrameOffset);
                            TotalCaptured = ReadCount - iNewFrameOffset;

                        }
                        else
                        {
                            TotalCaptured += ReadCount;
                        }
                    }
                    else
                    {
                        TotalCaptured += ReadCount;
                    }
                }while(UartGetChar() != 0x1B);
                /* finally close it */
                su_VideoCameraClose(0);
                if(pCaptureBuffer[0])
                    free(pCaptureBuffer[0]);
                if(pCaptureBuffer[1])
                    free(pCaptureBuffer[1]);
            }
            else
            {
                USBHPutString("Open video camera failed");
            }
        }
        else
        {
            USBHPutString("Video capture format is not supported");
        }
    }
}
#endif /* DEMO_VIDEO */


